/*
使用websocketpp库搭建服务器
    0. 编写各个事件的回调函数
    1. 实例化服务器对象
    2. 向服务器对象注册事件回调函数：握手成功，连接断开，收到websocket消息，收到http请求
    3. 初始化asio框架
    4. 启动地址重用
    5. 设置监听地址
    6. 开启获取新链接
    7. 启动服务器
*/

#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <iostream>

typedef websocketpp::server<websocketpp::config::asio> websocketsvr_t;

void onOpen(websocketsvr_t *server, websocketpp::connection_hdl hdl)
{
    std::cout << "onOpen" << std::endl;
}

void onClose(websocketsvr_t *server, websocketpp::connection_hdl hdl)
{
    std::cout << "onClose" << std::endl;
}

void onMessage(websocketsvr_t *server, websocketpp::connection_hdl hdl, websocketsvr_t::message_ptr msg)
{
    auto conn = server->get_con_from_hdl(hdl);
    // 2. 发送http响应
    const auto &request = conn->get_request();
    std::cout << request.get_method() << std::endl;
    std::cout << request.get_uri() << std::endl;
    std::cout << request.get_body() << std::endl;
    auto headers = request.get_headers();
    for (auto &header : headers)
    {
        std::cout << header.first << ": " << header.second << std::endl;
    }
    std::cout << "收到websocket消息: " << msg->get_payload() << std::endl;
    conn->send("回显: " + msg->get_payload(), websocketpp::frame::opcode::text);
}   

void onHttp(websocketsvr_t *server, websocketpp::connection_hdl hdl)
{
    // 1. 获取连接的对象
    auto conn = server->get_con_from_hdl(hdl);
    // 2. 发送http响应
    const auto &request = conn->get_request();
    std::cout << request.get_method() << std::endl;
    std::cout << request.get_uri() << std::endl;
    std::cout << request.get_body() << std::endl;
    auto headers = request.get_headers();
    for (auto &header : headers)
    {
        std::cout << header.first << ": " << header.second << std::endl;
    }
    conn->set_status(websocketpp::http::status_code::value::ok);
    conn->set_body("<html><body><h1>Hello, World!</h1></body></html>");
    conn->append_header("Content-Type", "text/html");
}
int main(int argc, char* argv[])
{
    websocketsvr_t server;

    server.clear_access_channels(websocketpp::log::alevel::all);

    server.set_open_handler(std::bind(onOpen, &server, std::placeholders::_1));
    server.set_close_handler(std::bind(onClose, &server, std::placeholders::_1));
    server.set_http_handler(std::bind(onHttp, &server, std::placeholders::_1));
    server.set_message_handler(std::bind(onMessage, &server, std::placeholders::_1, std::placeholders::_2));

    server.init_asio();

    server.set_reuse_addr(true);

    server.listen(9000);

    server.start_accept();

    server.run();
    return 0;
}